import os
import time
import cv2
import numpy as np
import pandas as pd
from keras.applications.vgg19 import VGG19
from keras.preprocessing import image
from keras.applications.vgg19 import preprocess_input
from keras.models import Model
from keras.layers import Dense
from sklearn.metrics import classification_report, roc_curve, auc
import matplotlib.pyplot as plt
from keras.utils import to_categorical
from keras.optimizers import Adam
from keras.losses import categorical_crossentropy

# Load VGG19 model
base_model = VGG19(weights='imagenet')
x = base_model.get_layer('fc2').output
output = Dense(2, activation='softmax')(x)  # new output layer
model = Model(inputs=base_model.input, outputs=output)

# Compile the model
model.compile(optimizer=Adam(), loss=categorical_crossentropy, metrics=['accuracy'])

# Print the model summary
model.summary()

# Function to detect and crop chest area
def detect_and_crop_chest(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    chest_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_fullbody.xml')
    chests = chest_cascade.detectMultiScale(gray, 1.1, 4)
    for (x, y, w, h) in chests:
        return image[y:y+h, x:x+w]
    return image  # return original image if no chest is detected

# Load and preprocess images
def load_images_from_folder(folder):
    images = []
    for filename in os.listdir(folder):
        img = cv2.imread(os.path.join(folder, filename))
        if img is not None:
            img = detect_and_crop_chest(img)
            img = cv2.resize(img, (224, 224))
            images.append(img)
    return images

# Load training images
train_dir = 'D:\\kaggle\\final\\data1\\train'
cancer_train_dir = os.path.join(train_dir, 'cancer')
normal_train_dir = os.path.join(train_dir, 'normal')

cancer_train_images = load_images_from_folder(cancer_train_dir)
normal_train_images = load_images_from_folder(normal_train_dir)

# Load testing images
test_dir = 'D:\\kaggle\\final\\data1\\test'
cancer_test_dir = os.path.join(test_dir, 'cancer')
normal_test_dir = os.path.join(test_dir, 'normal')

cancer_test_images = load_images_from_folder(cancer_test_dir)
normal_test_images = load_images_from_folder(normal_test_dir)

# Create labels
cancer_train_labels = [1 for _ in range(len(cancer_train_images))]
normal_train_labels = [0 for _ in range(len(normal_train_images))]

cancer_test_labels = [1 for _ in range(len(cancer_test_images))]
normal_test_labels = [0 for _ in range(len(normal_test_images))]

# Combine data
X_train = np.array(cancer_train_images + normal_train_images)
y_train = np.array(cancer_train_labels + normal_train_labels)

X_test = np.array(cancer_test_images + normal_test_images)
y_test = np.array(cancer_test_labels + normal_test_labels)

# Preprocess images
X_train = preprocess_input(X_train)
X_test = preprocess_input(X_test)

# Convert labels to categorical
y_train = to_categorical(y_train, num_classes=2)
y_test = to_categorical(y_test, num_classes=2)

# Train model
start_time = time.time()
model.fit(X_train, y_train, epochs=20, validation_data=(X_test, y_test))
end_time = time.time()

# Predict on test set
y_pred = model.predict(X_test)

# Convert predictions to labels
y_pred_labels = np.argmax(y_pred, axis=1)
y_test_labels = np.argmax(y_test, axis=1)

# Print classification report
print(classification_report(y_test_labels, y_pred_labels))

# Calculate and plot ROC curve and AUC
fpr, tpr, _ = roc_curve(y_test_labels, y_pred_labels)
roc_auc = auc(fpr, tpr)
plt.figure()
plt.plot(fpr, tpr, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic')
plt.legend(loc="lower right")
plt.show()

# Print program running time
print(f'Program running time: {end_time - start_time}')

'''
Epoch 1/10
10/10 [==============================] - 325s 32s/step - loss: 2123.0352 - accuracy: 0.5512 - val_loss: 7.2251 - val_accuracy: 0.7030
Epoch 2/10
10/10 [==============================] - 324s 32s/step - loss: 2.3960 - accuracy: 0.6436 - val_loss: 1.5230 - val_accuracy: 0.7030
Epoch 3/10
10/10 [==============================] - 511s 53s/step - loss: 1.0681 - accuracy: 0.6733 - val_loss: 1.5850 - val_accuracy: 0.2970
Epoch 4/10
10/10 [==============================] - 1377s 138s/step - loss: 0.8585 - accuracy: 0.5446 - val_loss: 0.7534 - val_accuracy: 0.7030
Epoch 5/10
10/10 [==============================] - 1267s 127s/step - loss: 0.6889 - accuracy: 0.6469 - val_loss: 0.6077 - val_accuracy: 0.7030
Epoch 6/10
10/10 [==============================] - 1251s 127s/step - loss: 0.6222 - accuracy: 0.7030 - val_loss: 0.6315 - val_accuracy: 0.7030
Epoch 7/10
10/10 [==============================] - 1237s 125s/step - loss: 0.8946 - accuracy: 0.6238 - val_loss: 0.8628 - val_accuracy: 0.7030
Epoch 8/10
10/10 [==============================] - 1192s 124s/step - loss: 0.7960 - accuracy: 0.6997 - val_loss: 4.5635 - val_accuracy: 0.3069
Epoch 9/10
10/10 [==============================] - 1370s 142s/step - loss: 1.5804 - accuracy: 0.5941 - val_loss: 0.6907 - val_accuracy: 0.7030
Epoch 10/10
10/10 [==============================] - 1146s 115s/step - loss: 0.6037 - accuracy: 0.7228 - val_loss: 0.4301 - val_accuracy: 0.9307
4/4 [==============================] - 106s 24s/step
              precision    recall  f1-score   support

           0       0.96      0.80      0.87        30
           1       0.92      0.99      0.95        71

    accuracy                           0.93       101
   macro avg       0.94      0.89      0.91       101
weighted avg       0.93      0.93      0.93       101

Program running time: 10010.355190753937
'''